package parser

import (
	"bufio"
	"fmt"
	"os"
	"regexp"
	"strings"
	"unicode"
)

// RedisStruct 表示需要生成Redis操作的结构体信息
type RedisStruct struct {
	idx             uint32
	Name            string  // 结构体名称
	ClientName      string  // dbClient or clClient
	DbStructName    string  //DBKnight
	PointStructName string  //db.Knight
	Type            string  // Redis类型(hash/set/map)
	KeyType         string  // 键类型
	BufferSize      int     // 缓冲区大小(如果有)
	Fields          []Field // 字段列表
	UniqueName      string  // 唯一字段名字
	UniqueType      string  // 唯一字段类型
}

// Field 表示结构体字段信息
type Field struct {
	Name     string // 字段名
	HumpName string // 驼峰名
	Type     string // 字段类型
	Number   int    // 字段编号
	IsUnique bool   // 是否唯一
}

// Parser proto文件解析器
type Parser struct {
	structs []RedisStruct
}

// NewParser 创建新的解析器
func NewParser() *Parser {
	return &Parser{
		structs: make([]RedisStruct, 0),
	}
}

// ParseFile 解析proto文件
func (p *Parser) ParseFile(fileName, protoFileName string) error {
	file, err := os.Open(fileName)
	if err != nil {
		return fmt.Errorf("打开文件失败: %v", err)
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	var currentStruct *RedisStruct
	ropRegex := regexp.MustCompile(`//\$<ROP redis\|(\w+)\|([^>]+)>`)
	//fieldRegex := regexp.MustCompile(`(\w+)\s+(\w+)\s*=\s*(\d+)(?:\s*;\s*//\$<ROP unique\s*>)?`)
	fieldRegex := regexp.MustCompile(`([\w\.]+)\s+(\w+)\s*=\s*(\d+)(?:\s*;\s*//\$<ROP unique\s*>)?`)
	messageBeginRegex := regexp.MustCompile(`^([^{]+)`)
	//messageEndRegex := regexp.MustCompile(`^([^}]+)`)

	idx := uint32(0)
	ropRunning := false
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())

		// 检查是否是Redis操作结构体
		if matches := ropRegex.FindStringSubmatch(line); len(matches) > 0 {
			idx++
			ropRunning = true

			// 解析Redis类型和参数
			redisType := matches[1]
			params := strings.Split(matches[2], "|")

			// 创建新的结构体
			currentStruct = &RedisStruct{
				idx:    idx,
				Type:   redisType,
				Fields: make([]Field, 0),
			}

			// 解析参数
			for _, param := range params {
				if strings.Contains(param, "buffer=") {
					tmpKey := ""
					fmt.Sscanf(param, "%s buffer=%d", &tmpKey, &currentStruct.BufferSize)
				}
				if strings.Contains(param, ":") {
					parts := strings.Split(param, ":")
					tmps := strings.Split(parts[1], " ")
					currentStruct.KeyType = strings.TrimSpace(tmps[0])
					//if len(tmps) > 1 && strings.Contains(tmps[1], "buffer=") {
					//	fmt.Sscanf(param, "buffer=%d", &currentStruct.BufferSize)
					//}
				}
			}
			continue
		}

		if !ropRunning {
			continue
		}

		// 如果是结构体定义行
		if strings.HasPrefix(line, "message ") && currentStruct != nil {
			tmpName := strings.TrimPrefix(line, "message ")
			if matches := messageBeginRegex.FindStringSubmatch(tmpName); len(matches) > 0 {
				currentStruct.Name = strings.TrimSpace(matches[1])
				currentStruct.ClientName = protoFileName + "Client"
				currentStruct.DbStructName = protoFileName + currentStruct.Name
				currentStruct.PointStructName = strings.ToLower(protoFileName) + "." + currentStruct.Name
			}
			//currentStruct.Name = strings.TrimSpace(strings.TrimRight(tmpName, "{"))
			continue
		}

		// 解析字段
		if matches := fieldRegex.FindStringSubmatch(line); len(matches) > 0 && currentStruct != nil {
			typ, name := matches[1], matches[2]
			if typ == "Op" {
				continue
			}
			field := Field{
				Name:     name,
				HumpName: toCamelCase(name),
				Type:     getFieldType(typ),
				Number:   0,
			}

			fmt.Sscanf(matches[3], "%d", &field.Number)

			// 检查是否是唯一字段
			if strings.Contains(line, "//$<ROP unique") {
				field.IsUnique = true
				//currentStruct.UniqueName = field.Name
				currentStruct.UniqueName = field.HumpName
				currentStruct.UniqueType = field.Type
			}

			currentStruct.Fields = append(currentStruct.Fields, field)
			continue
		}

		//rop消息结构体解析结束
		if line == "}" && currentStruct != nil {
			//fmt.Println("add struct ", currentStruct.Name, currentStruct.idx, currentStruct.BufferSize)
			p.structs = append(p.structs, *currentStruct)
			ropRunning = false
			currentStruct = nil
		}
	}

	return scanner.Err()
}

// GetRedisStructs 获取所有需要生成Redis操作的结构体
func (p *Parser) GetRedisStructs() []RedisStruct {
	return p.structs
}

// 驼峰名
func toCamelCase(s string) string {
	var result strings.Builder
	parts := strings.Split(s, "_")
	for _, part := range parts {
		if part == "" {
			continue
		}
		result.WriteString(strings.Title(part))
	}
	return result.String()
}

func CapitalizeFirstLetter(s string) string {
	if s == "" {
		return s
	}
	runes := []rune(s)
	runes[0] = unicode.ToUpper(runes[0])
	return string(runes)
}

var basicTypes = map[string]bool{
	"bool":       true,
	"string":     true,
	"int":        true,
	"int8":       true,
	"int16":      true,
	"int32":      true,
	"int64":      true,
	"uint":       true,
	"uint8":      true,
	"uint16":     true,
	"uint32":     true,
	"uint64":     true,
	"uintptr":    true,
	"byte":       true, // alias for uint8
	"rune":       true, // alias for int32
	"float32":    true,
	"float64":    true,
	"complex64":  true,
	"complex128": true,
}

func getFieldType(fieldType string) string {
	if basicTypes[fieldType] {
		return fieldType
	}
	if strings.HasPrefix(fieldType, "cl.") {
		return fieldType
	}
	return "db." + fieldType
}
